home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / driverss.zip / IPXPKT.ASM < prev    next >
Assembly Source File  |  1991-02-08  |  37KB  |  1,696 lines

  1. version    equ    2
  2.  
  3. ; Packet driver to simulate Ethernet on Novell IPX protocol.
  4. ;
  5. ; Paul Kranenburg
  6. ; Department of Computer Science
  7. ; University of Leiden
  8. ; Niels Bohrweg 1
  9. ; PO Box 9512
  10. ; 2300 RA Leiden
  11. ; The Netherlands
  12. ; e-mail: pk@cs.leidenuniv.nl
  13. ;
  14. ;
  15. ; File: ipxpkt.asm
  16. ;
  17. ;
  18. ; General description:
  19. ;
  20. ; Take destination from the Ethernet packet and feed it to IPX
  21. ; in the Event Control Block Immediate Address field.
  22. ;
  23. ; IPX packets are 576 bytes at most, 30 are needed for the IPX header
  24. ; leaving 546 bytes of user data. Another 4 bytes are used to describe
  25. ; fragments.
  26. ; If NO_OF_SND_BUFS is set to 1, this yields an MTU for this driver of 528.
  27. ; (546 - 4 - sizeof(Ether header)[=14]).
  28. ; If IPX trail is used another 32 bytes are lost (MTU = 496).
  29. ;
  30. ; If NO_OF_SND_BUFS is set to 3, the Ethernet packet is broken into at most
  31. ; 3 fragments. These are tagged with a Fragment id and shipped.
  32. ;
  33. ; On reception, fragments are kept on a linked list ordered by fragment number
  34. ; and keyed by source node address and fragment id.
  35. ; An IPX event is scheduled to allow for timeout of pending reassembly queues.
  36. ;
  37. ; If all fragments are reassembled, the client is called to provide a buffer for
  38. ; the packet.
  39. ;
  40. ; [ To save on buffer space, the driver could conceivably do with some minimum
  41. ;  number of buffers and call recv_find as soon as a fragment arrives, copy
  42. ;  the contents, and only call recv_copy when all fragments have arrived. However,
  43. ;  I don't think there is a way to notify the client in case a fragment gets lost.]
  44. ;
  45. ; In this code, the number of receive buffers (NO_OF_RCV_BUFS) has been set
  46. ; to 6 (a wild guess).
  47. ; This driver has yet to be tested in a gateway under heavy load. One probably
  48. ; needs more buffers in this case.
  49. ;
  50. ; Buffer space for the receive buffers is allocated after the "end_resident"
  51. ; label. There is a potential problem here: we start listening for packets
  52. ; using these buffers while still in the initialisation code, which is overlaid
  53. ; by the receive buffers. This is why interrupts are turned off wherever possible.
  54. ;
  55. ;
  56. ; CHANGELOG.
  57. ;
  58. ; 07/16/90
  59. ; Decoupled simulated ethernet address from IPX node address in routing tables,
  60. ; allowing for unique addresses in nets like ARCNET with only a one byte
  61. ; node address.
  62. ; Thanks to Robert Roll and Reid Sweatman of the University of Utah
  63. ; for pointing this out.
  64. ; IPXPKT accepts a command line option of the from `-n [<no_bytes>]' to specify
  65. ; the number of significant bytes in the IPX node address. If less then EADDR_LEN,
  66. ; the presented ethernet address will get supplemented with some bytes from
  67. ; the IPX node address to (hopefully) create a unique address among the nodes
  68. ; in the network involved.
  69. ; If `<no_bytes>' is omitted, the number of significant bytes will be set as the
  70. ; number of bytes left in the node address after stripping leading zeroes.
  71. ;
  72. ; 07/12/90
  73. ; Reorganize initialisation; do GET_ADDESS etc., before posting LISTEN's
  74. ;
  75. ; 05/16/90
  76. ; New socket number used when TRAIL enabled (0x6181).
  77. ; Enables co-existance of original and "TRAIL" versions of packet driver.
  78. ; You can start both an old and a new experimental driver in your gateway,
  79. ; but watch those IP subnet addresses.
  80. ;
  81. ; 05/15/90
  82. ; Corrected byte-order of IPX socket.
  83. ; Socket number NOT actually changed (== 0x6180, in dynamic range)
  84. ;
  85. ; 05/15/90
  86. ; Add dummy GET_LOCAL_TARGET call to force some traffic to IPX from a bridge.
  87. ; This will get the local net address to IPX. Define TRY_GET_LOCAL_TARGET if
  88. ; you want to use this.
  89. ;
  90. ; 05/07/90
  91. ; Add statistics gathering on various table lookups.
  92. ; Compile option STAT. Use ipxstat.c for display (derivative of version 5.0 `stat.c').
  93. ;
  94. ; 05/04/90
  95. ; Fixed case of register trashing in route code.
  96. ; Add IPX 32-byte trailer for bridge routing.
  97. ; Compile option TRAIL.
  98. ;
  99. ; 05/03/90
  100. ; Add routing table.
  101. ; Net/node addresses of incoming packets are put routing table along with
  102. ; immediate address field in ecb struct.
  103. ; Outgoing packets have the their net- and immediate address looked up
  104. ; in the table with the node address as key.
  105. ; Special case: broadcast packets are sent with packet type 0x14 through
  106. ; permanent entry in routing table.
  107. ;
  108. ; 05/03/90
  109. ; **REMOVED** 07/17/90
  110. ; Add compile option to declare receive buffer space at compile time.
  111. ; Compile option NOT_SO_SAVE; if defined, buffer space is allocated beginning at
  112. ; `end_resident' else space is reserved by compiler
  113. ;
  114. ; 05/02/90
  115. ; Merge `fill_ipxhdr' into `route'.
  116. ;
  117.  
  118. ;DEBUG            EQU    1
  119. TRY_GET_LOCAL_TARGET    EQU    1
  120. STAT            EQU    1
  121. TRAIL            EQU    1
  122. ETH_CONSTR        EQU    3
  123.  
  124.     include    defs.asm
  125.  
  126. MAX_IPX_LEN    =    576        ; Maximum packet size that can be
  127.                     ; shipped through IPX
  128. ifdef TRAIL
  129. IP_socket    =    08161h        ; Socket allocated for Blue book Ether
  130.                     ; on IPX with TRAILS (BYTE-SWAPPED)
  131. else
  132. IP_socket    =    08061h        ; Socket allocated for
  133.                     ; Blue book Ether on IPX (BYTE-SWAPPED)
  134. endif
  135.  
  136. PEP        =    4        ; Packet Exchange Packet (ipx_type)
  137. GBP        =    014h        ; Global Broadcast Packet (ipx_type)
  138. RTE_TICK    =    37        ; Interval between calls to rte_ticker,
  139.                     ; 37 is approx. 2 seconds
  140.  
  141. ipx_header    struc
  142. ipx_chksum    dw    ?        ; Checksum, network byte order
  143. ipx_len        dw    ?        ; Packet length,   "
  144. ipx_prot    db    ?        ; Transport protocol
  145. ipx_type    db    ?        ; Packet type
  146. ipx_destnet    db    4 dup(?)    ; Destination network
  147. ipx_destnode    db    6 dup(?)    ; Destination node
  148. ipx_destsock    dw    ?        ; Destination socket
  149. ipx_srcnet    db    4 dup(?)    ; Source network
  150. ipx_srcnode    db    6 dup(?)    ; Source node
  151. ipx_srcsock    dw    ?        ; Source socket
  152. ifdef TRAIL
  153. ipx_trail    db    8 * 4 dup(?)    ; IPX gateway trail
  154. endif
  155. ipx_header    ends
  156.  
  157.  
  158. frag_dscr    struc
  159. frag_addr    dd    ?        ; Fragment address
  160. frag_size    dw    ?        ; Fragment size
  161. frag_dscr    ends
  162.  
  163. ecb        struc
  164. ecb_link    dd    ?        ;
  165. ecb_esr        dd    ?        ; Event Service Routine
  166. ecb_inuse    db    ?        ; In Use field
  167. ecb_cmplt    db    ?        ; Completion Code
  168. ecb_sock    dw    ?        ; Socket Number
  169. ecb_ipxwork    db    4 dup (?)    ; IPX reserved workspace
  170. ecb_drvwork    db    12 dup (?)    ; Driver reserved workspace
  171. ecb_ia        db    6 dup (?)    ; Immediate Address
  172. ecb_fragcnt    dw    ?        ; Fragment count
  173. ;ecb_dscr    =    $        ; Start of Fragment descriptor list
  174. ecb        ends
  175.  
  176. aes_ecb        struc
  177. aes_link    dd    ?        ;
  178. aes_esr        dd    ?        ; Event Service Routine
  179. aes_inuse    db    ?        ; In Use field
  180. aes_work    db    5 dup (?)    ; Driver reserved workspace
  181. aes_ecb        ends
  182.  
  183.  
  184. ether_frag    struc
  185. ef_fragno    db    ?        ; This fragment number
  186. ef_fragtot    db    ?        ; Total number of fragments comprising the packet
  187. ef_fragid    dw    ?        ; Fragment Id
  188. ether_frag    ends
  189.  
  190. queue_entry    struc
  191. q_aes        db (size aes_ecb) dup(?); AES structure, used for reassembly timeouts
  192. q_filler    db    0
  193. q_count        db    0        ; Number of fragments currently queued here
  194. q_net        db    SIZE ipx_srcnet dup(?)
  195. q_node        db    SIZE ipx_srcnode dup(?)    ; Source node
  196. q_fragid    dw    ?            ; Fragment Id
  197. q_len        dw    ?            ; Total length of user data queued here
  198. q_ecb        dd    ?            ; Ecb pointer to fragment
  199. queue_entry    ends
  200.  
  201. u_buf        struc
  202. u_ecb        db (size ecb) dup(?)
  203. u_ipx_frag    db (size frag_dscr) dup(?)
  204. u_frag_frag    db (size frag_dscr) dup(?)
  205. u_data_frag    db (size frag_dscr) dup(?)
  206. u_ipx        db (size ipx_header) dup(?)
  207. u_ether_frag    db (size ether_frag) dup(?)
  208. ;u_data        LABEL        BYTE
  209. u_buf        ends
  210.  
  211. MAX_PAYLOAD    =    MAX_IPX_LEN - SIZE ipx_header - SIZE ether_frag
  212.  
  213. ;routing table entry
  214. rt_ent        struc
  215. rt_ether    db    EADDR_LEN dup(?)    ; Ethernet address of target: lookup key
  216. rt_net        db    SIZE ipx_srcnet dup(?)    ; Net address of target
  217. rt_node        db    SIZE ipx_srcnode dup(?)    ; Node address of target
  218. rt_gate        db    SIZE ecb_ia dup(?)    ; First hop on route to above
  219. rt_x_pkt    db    ?        ; IPX packet type to send packet with
  220. ;;rt_trail    db    ?        ; This node uses IPX trail
  221. rt_age        dw    ?        ; Usage indicator for this entry
  222. rt_ent        ends
  223.  
  224. print$        macro    string
  225. ;---------------------------------------;
  226. ;  sends $ terminated string to screen  ;
  227. ;---------------------------------------;
  228.         push    dx
  229.         mov     ah,9
  230.         mov     dx,offset &string&      ; print $ terminated string
  231.         int     21h
  232.         pop    dx
  233.         endm
  234.  
  235. ; ipx function numbers
  236. OPEN_SOCKET        =    0
  237. CLOSE_SOCKET        =    1
  238. GET_LOCAL_TARGET    =    2
  239. SEND_PACKET        =    3
  240. LISTEN            =    4
  241. SCHEDULE_EVENT        =    5
  242. CANCEL_EVENT        =    6
  243. SCHEDULE_SPECIAL_EVENT    =    7
  244. GET_NODE_ADDRESS    =    9
  245. RELINQUISH        =    0Ah
  246.  
  247. call_ipx    macro    opcode,reg1,reg2,reg3,reg4,reg5,reg6,reg7,reg8
  248.         irp N, <reg1,reg2,reg3,reg4,reg5,reg6,reg7,reg8>
  249.             ifnb <N>
  250.                 push    N
  251.             endif
  252.         endm
  253.         mov    bx, opcode
  254. ;better be save here and use Code segment explicitly
  255.         call    cs:IPXentry
  256.         irp N, <reg8,reg7,reg6,reg5,reg4,reg3,reg2,reg1>
  257.             ifnb <N>
  258.                 pop    N
  259.             endif
  260.         endm
  261.         endm
  262.  
  263. repmov        macro    count
  264.         rept    (count) / 2
  265.         movsw
  266.         endm
  267.         rept    (count) MOD 2
  268.         movsb
  269.         endm
  270.         endm
  271.  
  272. ifdef STAT
  273. statinc        macro    loc
  274.         local    a
  275. ;affects flags register (NOT carry)
  276.         inc    cs:loc
  277.         jnz    a
  278.         inc    cs:loc+2
  279.     a:
  280.         endm
  281. else
  282. statinc        macro    loc
  283.         endm
  284. endif
  285.  
  286. code    segment    word public
  287.     assume    cs:code, ds:code
  288.  
  289. IPXentry    dd    ?
  290. FragmentID    dw    ?
  291.  
  292. my_net_address    db    4 dup(?)    ; contiguous 10 byte addrss-area as IPX wants it
  293. my_node_address    db    6 dup(?)
  294.  
  295. no_bytes    dw    EADDR_LEN, 0    ; number of significant bytes in IPX node address
  296.                     ; set as command line option.
  297. init_cmplt    dw    0
  298.  
  299. dummy        db    10 dup(0ffh)    ; dummy addr/socket
  300.         dw    05104h        ; what socket to use (???)
  301.         db    6 dup(?)    ; returned address
  302.  
  303.  
  304. NO_OF_FRAGMENTS    =    3
  305. NO_OF_RCV_BUFS    =    6
  306. NO_OF_SND_BUFS    =    3
  307. NO_OF_QUEUES    =    NO_OF_RCV_BUFS        ; ????
  308. NO_OF_RTES    =    30
  309.  
  310. reass_queues    queue_entry    NO_OF_QUEUES dup(<>)
  311.  
  312. rcv_bufs    u_buf        NO_OF_RCV_BUFS dup(<>)
  313. snd_bufs    u_buf        NO_OF_SND_BUFS dup(<>)
  314.  
  315. ifdef STAT
  316. ;;        org    ($ + 1) and 0fffeh
  317. ; keep ID string an even number of bytes (including terminating zero and count)
  318.         db    "RTE_TABL", 0, NO_OF_RTES
  319. endif
  320. rte        rt_ent        NO_OF_RTES dup(<>)
  321. rte_end        dw        0
  322. rte_scache    dw        0
  323. rte_rcache    dw        0
  324. rte_aes        aes_ecb        <>
  325.  
  326. ifdef STAT
  327. ;;        org    ($ + 1) and 0fffeh
  328.         db    "IPXSTAT", 0    ; keep this string an even number of bytes
  329. queue_full    dw    2 dup(0)
  330. route_drop    dw    2 dup(0)
  331. scache_miss    dw    2 dup(0)
  332. rcache_miss    dw    2 dup(0)
  333. route_loops    dw    2 dup(0)
  334. route_lookups    dw    2 dup(0)
  335. endif
  336.  
  337. ;-------------------------------------------------------------------------------
  338. ;
  339. ; local functions
  340. ;
  341. ; A NOTE on style:
  342. ;
  343. ; the functions below seem to liberally load and reload pointers into
  344. ; a register pair involving the ds segment register.
  345. ; In fact, ds almost always contains the code segment as "assumed" above.
  346. ; Also, the distinction between pointers to ecb's and ubuf's / queue's is not made
  347. ; most of the time. This is alright as long as the ecb structures remain the first
  348. ; ones declared in u_buf and queue.
  349. ; Need to work out a consistent register usage some day...
  350. ;
  351.  
  352. find_queue    proc    near
  353.     ;
  354.     ; Find/allocate a queue-entry where an ether fragment can be stored.
  355.     ; On entry: es:di -> source node address.
  356.     ;           dx == fragment Id.
  357.     ; Out: si == 0 if no queue entry available,
  358.     ;      otherwise: (ds:)si -> allocated queue-entry.
  359.     ; Must be called with interrupts disabled.
  360.  
  361.     push    cx
  362.     push    bx
  363.     mov    cx, NO_OF_QUEUES
  364.     lea    si, reass_queues
  365.     mov    bx, 0
  366.  
  367. fq_loop:
  368.     mov    al, [si].q_count
  369.     or    al, al
  370.     jnz    fq_1
  371.     or    bx, bx        ;
  372.     jne    fq_2        ; remember first entry not in use
  373.     mov    bx, si        ;
  374.     jmp    short fq_2
  375.  
  376. fq_1:
  377.     mov    ax, cx        ; can use AX in stead of `push cx'
  378.     push    si
  379.     push    di
  380.     add    si, q_net
  381.     mov    cx, SIZE q_net + SIZE q_node
  382.     cld
  383.     repe    cmpsb
  384.     pop    di
  385.     pop    si
  386.     mov    cx, ax
  387.     jne    fq_2
  388.     cmp    dx, [si].q_fragid
  389.     jne    fq_2
  390.     jmp    short fq_x
  391.  
  392. fq_2:
  393.     add    si, SIZE queue_entry
  394.     loop    fq_loop
  395.  
  396.     mov    si, bx
  397.  
  398. ifdef STAT
  399.     or    si, si
  400.     jnz    fq_stat_1
  401.     statinc    queue_full
  402. fq_stat_1:
  403. endif
  404.  
  405. fq_x:
  406.     pop    bx
  407.     pop    cx
  408.     ret
  409. find_queue    endp
  410.  
  411. enqueue        proc    near
  412.     ; Queue an etherpacket fragment on appropriate queue
  413.     ; On entry: es:si -> received ecb.
  414.     ;           cx = length of data in this fragment
  415.     ; Out: carry set if no space available.
  416.     ;      zero flag set if packet on queue complete.
  417.     ;      ds:si -> queue_entry on which fragment was queued.
  418.  
  419.     push    si
  420.     push    es
  421.     mov    ax, 0
  422.     mov    es:[si].u_ecb.ecb_link.offs, ax        ; clear link-field
  423.     mov    es:[si].u_ecb.ecb_link.segm, ax
  424.     mov    di, si                    ; es:di -> ecb
  425.     mov    dx, es:[si].u_ether_frag.ef_fragid
  426.     push    di
  427. ;    lea    di, es:[si].u_ipx.ipx_srcnode
  428.     lea    di, es:[si].u_ipx.ipx_srcnet
  429.     call    find_queue
  430.     pop    di
  431.  
  432.     or    si, si
  433.     jnz    enq_0
  434.     add    sp, 4
  435.     stc
  436.     ret
  437.  
  438. enq_0:
  439.     mov    dl, es:[di].u_ether_frag.ef_fragno
  440.     mov    dh, es:[di].u_ether_frag.ef_fragtot
  441.     cmp    [si].q_count, 0
  442.     jne    enq_3
  443.  
  444. ;this is the first fragment we receive
  445.     call    rte_enter        ; record their route
  446.     pop    [si].q_ecb.segm
  447.     pop    [si].q_ecb.offs
  448.     mov    [si].q_len, cx
  449.     mov    [si].q_count, 1
  450.     cmp    dh, 1            ;
  451.     jne    enq_1            ; short cut if fragment count == 1.
  452.     clc
  453.     ret
  454.  
  455. ;initialise queue structure a bit more...
  456. enq_1:
  457.     mov    ax, es:[di].u_ether_frag.ef_fragid
  458.     mov    [si].q_fragid, ax
  459.  
  460. ;copy source node address
  461.     mov    bx, SIZE q_net + SIZE q_node - 1
  462.  
  463. enq_2:
  464. ;    mov    al, es:[di+bx].u_ipx.ipx_srcnode
  465.     mov    al, es:[di+bx].u_ipx.ipx_srcnet
  466.     mov    ds:[si+bx].q_net, al
  467.     sub    bx, 1
  468.     jnc    enq_2
  469.  
  470.     mov    ax, cs
  471.     mov    [si].q_aes.aes_esr.segm, ax
  472.     mov    [si].q_aes.aes_esr.offs, offset reass_timeout
  473.     mov    ax, ds
  474.     mov    es, ax
  475.     mov    ax, 2            ; two ticks to timeout
  476.     call_ipx    SCHEDULE_SPECIAL_EVENT,si,dx
  477.     cmp    dh, [si].q_count
  478.     clc
  479.     ret
  480.  
  481. ; add ecb to existing queue, keep list ordered by fragment number.
  482. enq_3:
  483.     lea    ax, [si].q_ecb
  484.     push    ax            ; put link field address on stack
  485.     push    ds
  486.     les    di, [si].q_ecb
  487.  
  488. enq_4:
  489.     mov    ax, es            ; are we at end of list?
  490.     or    ax, di
  491.     jz    enq_5
  492.     cmp    dl, es:[di].u_ether_frag.ef_fragno    ; link after this frag?
  493.     jb    enq_5
  494.     add    sp, 4
  495. ;    lea    ax, es:[di].u_ecb.ecb_link
  496. ;    push    ax
  497.     push    di                    ; push `prev'-link
  498.     push    es
  499.     les    di, es:[di].u_ecb.ecb_link        ; load `next'-link
  500.     jmp    enq_4
  501.  
  502. ; enter here with two addresses on the stack:
  503. ;    1) address of ecb to link in
  504. ;    2) address of link field after which to link
  505. ; es:di contains the "next" link.
  506.  
  507. enq_5:
  508.     mov    ax, es                    ; temp = next
  509.     mov    bx, di
  510.     pop    es                    ; get prev
  511.     pop    di
  512.     pop    es:[di].segm                ; prev->next = this one
  513.     pop    es:[di].offs
  514.     les    di, es:[di]                ; load `this one'
  515.     mov    es:[di].u_ecb.ecb_link.segm, ax        ; `this one'->next = temp
  516.     mov    es:[di].u_ecb.ecb_link.offs, bx
  517.     add    [si].q_len, cx                ; update total queued data
  518.     inc    [si].q_count                ; update fragcount
  519.     cmp    dh, [si].q_count            ; return `zero' if all there
  520.     clc
  521.     ret
  522.  
  523. enqueue        endp
  524.  
  525. dequeue        proc    near
  526.     ; Send reassembled packet to client and reschedule receive buffers.
  527.     ; On entry: ds:si -> queue.
  528.  
  529.     mov    cx, [si].q_len
  530.     les    di, [si].q_ecb
  531.     les    di, es:[di].u_data_frag.frag_addr
  532.     add    di, 2 * EADDR_LEN
  533.  
  534.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  535.     mov    ax, es:[di]
  536.     xchg    ah, al
  537.     cmp     ax, 1500
  538.     ja    BlueBookPacket
  539.     inc    di            ;set di to 802.2 header
  540.     inc    di
  541.     mov    dl, IEEE8023
  542. BlueBookPacket:
  543.  
  544.     push    si
  545.     call    recv_find
  546.     pop    si
  547.     mov    ax, es
  548.     or    ax, di
  549.     jz    deq_2
  550.  
  551.     mov    dh, [si].q_count
  552.     mov    cx, [si].q_len
  553.     push    si            ; save our queue address
  554.     push    ds
  555.     push    di            ; save their buffer address
  556.     push    es
  557.     push    cx
  558.     lds    si, ds:[si].q_ecb
  559.     cld
  560.  
  561. ;all set, es:di -> user buffer, ds:si -> first fragment
  562. ;??? save count and source pointer for call to recv_copy
  563.  
  564. deq_1:
  565.     mov    cx, ds:[si].u_ipx.ipx_len
  566.     xchg    cl, ch
  567.     sub    cx, (SIZE ipx_header + SIZE ether_frag)
  568.     push    si
  569.     push    ds
  570.     lds    si, ds:[si].u_data_frag.frag_addr
  571.     rep    movsb
  572.     pop    ds
  573.     pop    si
  574.     lds    si, ds:[si].u_ecb.ecb_link
  575.     dec    dh
  576.     jnz    deq_1
  577.  
  578.     pop    cx            ; recover packet length and address
  579.     pop    ds            ; for completion call
  580.     pop    si            ;
  581.     call    recv_copy
  582.  
  583.     pop    ds            ; recover queue address
  584.     pop    si            ;
  585.  
  586. deq_2:
  587.     mov    ax, ds
  588.     mov    es, ax
  589.     call_ipx    CANCEL_EVENT,si
  590.  
  591.     push    si
  592.     mov    dh, [si].q_count
  593.     les    si, ds:[si].q_ecb
  594.  
  595. deq_3:
  596.     mov    bx, es:[si].ecb_link.offs
  597.     mov    cx, es:[si].ecb_link.segm
  598.     call    listen_proc
  599.     mov    si, bx
  600.     mov    es, cx
  601. ;    les    si, es:[si].u_ecb.ecb_link
  602.     dec    dh
  603.     jnz    deq_3
  604.     pop    si
  605.     mov    [si].q_count, 0
  606.     ret
  607. dequeue        endp
  608.  
  609. reass_timeout    proc    far
  610.     ; Called by AES when reassembly timeout occurs.
  611.     ; On entry: es:si pointer to ecb.
  612.     ;
  613.  
  614.     push    ds
  615.     mov    ax, cs
  616.     mov    ds, ax
  617.     push    si
  618.     push    es
  619.     mov    dh, es:[si].q_count
  620.     les    si, es:[si].q_ecb
  621.  
  622. reass_to_3:
  623.     mov    bx, es:[si].ecb_link.offs
  624.     mov    cx, es:[si].ecb_link.segm
  625.     call    listen_proc
  626.     mov    si, bx
  627.     mov    es, cx
  628.     dec    dh
  629.     jnz    reass_to_3
  630.  
  631.     pop    es
  632.     pop    si
  633.     mov    es:[si].q_count, 0
  634.  
  635.     pop    ds
  636.     ret
  637. reass_timeout    endp
  638.  
  639. receiver    proc    far
  640.     ;
  641.     ; On entry: es:si -> ecb.
  642.     ;
  643.  
  644.     push    ds
  645.     mov    ax, cs
  646.     mov    ds, ax
  647.     mov    al, es:[si].u_ecb.ecb_cmplt
  648.     or    al, al
  649.     jnz    receiver_err
  650.  
  651.     cmp    es:[si].u_ecb.ecb_fragcnt, NO_OF_FRAGMENTS
  652.     jne    receiver_err
  653.  
  654. ;IPX receives its own broadcasts because
  655. ;source and destination sockets are the same
  656. ;if ours, ignore
  657.  
  658.     mov    ax, si
  659.     mov    di, si
  660.     add    di, ecb_ia
  661.     lea    si, my_node_address
  662.     mov    cx, SIZE my_node_address
  663.     cld
  664.     repe    cmpsb
  665.     mov    si, ax
  666.     jz    receiver_x
  667.  
  668.     mov    cx, es:[si].u_ipx.ipx_len
  669.     xchg    cl, ch
  670.     sub    cx, (SIZE ipx_header + SIZE ether_frag)
  671.     jbe    receiver_err
  672.  
  673.     call    enqueue
  674.     jc    receiver_err
  675.     jnz    rec_1
  676.     call    dequeue
  677.  
  678. rec_1:
  679.     pop    ds
  680.     cli
  681.     ret
  682.  
  683. receiver_err:
  684.     call    count_in_err
  685.  
  686. receiver_x:
  687.     call    listen_proc        ; post listen again
  688.     pop    ds
  689.     cli            ; must return with interrupts disabled, says Novell.
  690.     ret
  691. receiver    endp
  692.  
  693. listen_proc    proc    near
  694.     ;
  695.     ; Post to u_buf for reception.
  696.     ; On entry: es:si -> receive-ecb
  697.     ;
  698.  
  699.     push    bx
  700.  
  701. ;fill in ecb
  702.     mov    es:[si].u_ecb.ecb_esr.offs, offset receiver
  703.     mov    ax, cs
  704.     mov    word ptr es:[si].u_ecb.ecb_esr.segm, ax
  705.     mov    es:[si].u_ecb.ecb_sock, IP_socket
  706.     call_ipx    LISTEN,es,si,di,dx,cx
  707.  
  708.     pop    bx
  709.     ret
  710.  
  711. listen_proc    endp
  712.  
  713. rte_ticker    proc    far
  714.     ;
  715.     ; ESR service routine called by AES
  716.     ; Ages all entries in routing table
  717.     ; executes entirely with disabled interrupts
  718.     ;
  719.     ; On entry: es:si -> ecb
  720.  
  721.     push    ds
  722.     mov    ax, cs
  723.     mov    ds, ax
  724.  
  725.     mov    dx, rte_end
  726.     lea    di, rte
  727.  
  728. rtick_1:
  729.     add    di, SIZE rt_ent        ; leave broadcast entry alone
  730.     cmp    di, dx
  731.     jae    rtick_done
  732.     mov    ax, [di].rt_age
  733.     add    ax, 1
  734.     jo    rtick_1
  735.     mov    [di].rt_age, ax
  736.     jmp    rtick_1
  737.  
  738. ;re-schedule ecb
  739. rtick_done:
  740.     mov    ax, RTE_TICK
  741.     call_ipx    SCHEDULE_SPECIAL_EVENT
  742.     pop    ds
  743.     ret
  744. rte_ticker    endp
  745.  
  746. rte_enter    proc    near
  747.     ;
  748.     ; Enter route to table
  749.     ; On entry: es:di -> ecb
  750.     ;
  751.     assume    ds:nothing, es:nothing
  752.  
  753.     push    bx
  754.     push    cx
  755.     push    dx
  756.     push    si
  757.     push    ds
  758.     push    di
  759.     push    es
  760.  
  761.     les    di, es:[di].u_data_frag.frag_addr
  762.     add    di, EADDR_LEN            ; es:di -> src node address
  763.     mov    bx, rte_rcache            ; global, last succesful entry
  764.     call    rte_find            ; will set DS to code seg
  765.     jc    ert_1
  766.  
  767. ifdef STAT
  768.     cmp    rte_rcache, si
  769.     je    ert_stat_1
  770.     statinc    rcache_miss
  771. ert_stat_1:
  772. endif
  773.  
  774.     mov    rte_rcache, si
  775.     jmp    ert_x                ; we already have route to src
  776.  
  777. ert_1:
  778. ;not in table, find free entry
  779. ;    mov    ax, cs
  780. ;    mov    ds, ax                ; ds == code
  781.  
  782.     lea    dx, rte
  783.     add    dx, SIZE rte            ; dx -> beyond rte
  784.     mov    bx, rte_end            ;
  785.     add    rte_end, SIZE rt_ent        ; take the chance
  786.     cmp    bx, dx                ; check whether table full
  787.     jb    ert_2
  788.     sub    rte_end, SIZE rt_ent        ; undo guess
  789.     call    kill_route            ; will leave freed entry in bx
  790.  
  791. ert_2:
  792. ;insert addresses in ecb and ipx into routing table
  793. ; $%#@, must swap registers for string operations
  794. ;
  795.     cld
  796.     mov    ax, ds
  797.     mov    cx, es
  798.     mov    es, ax
  799.     mov    ds, cx
  800.     mov    si, di                ; ds:si -> source address
  801.     mov    di, bx                ; es:di -> rt_ent
  802.  
  803.     add    di, rt_ether
  804.  
  805.     repmov  <SIZE rt_ether>
  806.  
  807.     pop     ds                ; recover ecb from stack
  808.     pop     si                ;
  809.     push    si
  810.     push    ds
  811.  
  812.     mov    ax, si
  813.  
  814.     add    si, u_ipx + ipx_srcnet        ; record source net+node
  815.     repmov    <SIZE rt_net + SIZE rt_node>
  816.  
  817.     mov    si, ax                ; restore si to start of ecb
  818.     add    si, ecb_ia            ; record immediate address
  819.     repmov    <SIZE rt_gate>
  820.  
  821.     mov    es:[bx].rt_x_pkt, PEP        ; packet type
  822.     mov    es:[bx].rt_age, 10        ; usage count (XXX)
  823.  
  824. ert_x:
  825.     pop    es
  826.     pop    di
  827.     pop    ds
  828.     pop    si
  829.     pop    dx
  830.     pop    cx
  831.     pop    bx
  832.     ret
  833. rte_enter    endp
  834.  
  835. kill_route    proc    near
  836.     ;
  837.     ; Delete entry in route table with highest rt_age field
  838.     ; Out: bx -> route entry freed
  839.     ;
  840.  
  841.     push    cx
  842.     push    dx
  843.     push    di
  844.     lea    di, rte
  845.     add    di, SIZE rt_ent        ; leave broadcast entry alone
  846.  
  847.     mov    dx, rte_end
  848.     mov    bx, di
  849.     mov    cx, 0
  850.  
  851. krt_1:
  852.     cmp    di, dx
  853.     je    krt_done
  854.     mov    ax, [di].rt_age
  855.     cmp    ax, cx
  856.     jbe    krt_2
  857.     mov    cx, ax
  858.     mov    bx, di
  859.  
  860. krt_2:
  861.     add    di, SIZE rt_ent
  862.     jmp    krt_1
  863.  
  864. krt_done:
  865. ifdef STAT
  866.     statinc    route_drop
  867. endif
  868.     pop    di
  869.     pop    dx
  870.     pop    cx
  871.     ret
  872. kill_route    endp
  873.  
  874.  
  875. rte_find    proc    near
  876.     ;
  877.     ; Find a route for address
  878.     ; On entry: es:di -> target address we are looking for (EADDR_LEN bytes)
  879.     ;           bx -> entry to start search
  880.     ; Out: ds:si -> route table entry, or carry set if not found
  881.     ;
  882.     assume    ds:code, es:nothing
  883.  
  884.     push    bx
  885.     push    dx
  886.     mov    ax, cs        ; cs == code segment
  887.     mov    ds, ax
  888.  
  889.     mov    dx, rte_end    ; global, points to first invalid rte entry
  890.     mov    ax, bx        ; ax == stopper
  891.     cld
  892.  
  893. frt_1:
  894. ifdef STAT
  895.     statinc    route_loops
  896. endif
  897.     mov    si, bx        ;
  898.     add    si, rt_ether    ; si -> rt_ether field (= key) of current rte-entry
  899.     push    di        ; save di
  900.     mov    cx, SIZE rt_ether
  901.     repe    cmpsb
  902.     pop    di
  903.     je    frt_x        ; compare ok, report succes
  904.     add    bx, SIZE rt_ent    ; next rte-entry
  905.     cmp    bx, dx
  906.     jb    frt_2
  907.     lea    bx, rte        ; end of valid entries, wrap around
  908. frt_2:
  909.     cmp    bx, ax
  910.     jne    frt_1
  911.     stc            ; back where we started, report failure
  912.  
  913. ;found, update cache and prepare output
  914. frt_x:
  915.     mov    si, bx
  916.  
  917. ifdef STAT
  918.     statinc    route_lookups
  919. endif
  920.     pop    dx
  921.     pop    bx
  922.     ret
  923. rte_find    endp
  924.  
  925. route    proc    near
  926.     ;
  927.     ; Determine where to send the packet
  928.     ; On entry: ds:si -> user data, es:di -> ecb
  929.     ;
  930.     assume    ds:nothing, es:nothing
  931.  
  932.     push    bx
  933.     push    cx
  934.     push    ds
  935.     push    si
  936.  
  937. ;find entry in routing table, in: es:di, out: ds:si -> pointer to table entry
  938.  
  939.     push    di
  940.     push    es
  941.     mov    ax, ds            ;
  942.     mov    es, ax            ; es:di -> target address
  943.     mov    di, si            ;
  944.  
  945.     mov    bx, rte_scache        ; global, last succesful entry
  946.     call    rte_find
  947.     pop    es
  948.     pop    di
  949.     jc    route_x
  950.  
  951. ifdef STAT
  952.     cmp    rte_scache, si
  953.     je    route_stat_1
  954.     statinc    scache_miss
  955. route_stat_1:
  956. endif
  957.  
  958.     mov    rte_scache, si        ; remember this entry
  959.     mov    ax, ds:[si].rt_age    ;
  960.     sub    ax, 1            ; decrement usage
  961.     jc    route_1
  962.     mov    ds:[si].rt_age, ax
  963.  
  964. route_1:
  965.     cld
  966.     mov    bx, di            ; remember ecb in BX
  967.  
  968. ifdef TRAIL
  969. ;clear ipx trail fields
  970.     add    di, u_ipx.ipx_trail
  971.     mov    ax, 0
  972.     mov    cx, (SIZE ipx_trail) / 2
  973.     rep    stosw
  974.  
  975.     mov    di, bx
  976. endif
  977.  
  978. ;fill in packet type and destination socket
  979.     mov    al, ds:[si].rt_x_pkt
  980.     mov    es:[di].u_ipx.ipx_type, al    ;PEP
  981.     mov    es:[di].u_ipx.ipx_destsock, IP_socket
  982.  
  983. ;fill in full destination adress
  984.     mov    ax, si            ; save si
  985.     add    si, rt_net
  986.     add    di, u_ipx.ipx_destnet
  987.     repmov    <SIZE ipx_destnet + SIZE ipx_destnode>
  988.     mov    si, ax            ; restore si, di
  989.     mov    di, bx            ;
  990.  
  991. ;fill in immediate address
  992.     add    di, ecb_ia
  993.     add    si, rt_gate
  994.     repmov    <SIZE ecb_ia>
  995.     mov    di, bx            ;
  996.  
  997. route_x:
  998.     pop    si
  999.     pop    ds
  1000.     pop    cx
  1001.     pop    bx
  1002.     ret
  1003. route    endp
  1004.  
  1005.     public    int_no
  1006. int_no    db    0,0,0,0            ;must be four bytes long for get_number.
  1007.  
  1008.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  1009. driver_class    db    BLUEBOOK, IEEE8023, 0        ;from the packet spec
  1010. driver_type    db    1        ;from the packet spec
  1011. driver_name    db    'IPX',0        ;name of the driver.
  1012. driver_function    db    2
  1013. parameter_list    label    byte
  1014.     db    1    ;major rev of packet driver
  1015.     db    9    ;minor rev of packet driver
  1016.     db    14    ;length of parameter list
  1017.     db    EADDR_LEN    ;length of MAC-layer address
  1018.   if NO_OF_SND_BUFS eq 1
  1019.     dw    MAX_PAY_LOAD - 2 * EADDR_LEN - 2    ;MTU, including MAC headers
  1020.   else
  1021.     dw    GIANT    ;MTU, including MAC headers
  1022.   endif
  1023.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  1024.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  1025.     dw    0    ;(# of successive xmits) - 1
  1026. int_num    dw    0    ;Interrupt # to hook for post-EOI
  1027.             ;processing, 0 == none,
  1028.  
  1029.     public    rcv_modes
  1030. rcv_modes    dw    4        ;number of receive modes in our table.
  1031.         dw    0,0,0,rcv_mode_3
  1032.  
  1033.     public    as_send_pkt
  1034. ; The Asynchronous Transmit Packet routine.
  1035. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  1036. ;   interrupts possibly enabled.
  1037. ; Exit with nc if ok, or else cy if error, dh set to error number.
  1038. ;   es:di and interrupt enable flag preserved on exit.
  1039. as_send_pkt:
  1040.     ret
  1041.  
  1042.     public    drop_pkt
  1043. ; Drop a packet from the queue.
  1044. ; Enter with es:di -> iocb.
  1045. drop_pkt:
  1046.     assume    ds:nothing
  1047.     ret
  1048.  
  1049.     public    xmit
  1050. ; Process a transmit interrupt with the least possible latency to achieve
  1051. ;   back-to-back packet transmissions.
  1052. ; May only use ax and dx.
  1053. xmit:
  1054.     assume    ds:nothing
  1055.     ret
  1056.  
  1057.  
  1058.     public    send_pkt
  1059. send_pkt:
  1060. ;enter with ds:si -> packet, cx = packet length.
  1061. ;exit with nc if ok, or else cy if error, dh set to error number.
  1062.     assume    ds:nothing
  1063.     push    es
  1064.     push    di
  1065.     mov    ax, cs
  1066.     mov    es, ax
  1067.  
  1068. ;first, compute number of fragments needed, keep in dx
  1069.     mov    dx, 0
  1070.     mov    ax, cx
  1071.  
  1072. snd_1:
  1073.     inc    dx
  1074.     sub    ax, MAX_PAYLOAD
  1075.     jnc    snd_1
  1076.  
  1077. ;can we handle this amount?
  1078.     cmp    dx, NO_OF_SND_BUFS
  1079.     jbe    snd_frags_ok
  1080.  
  1081. snd_err:
  1082.     call    count_out_err
  1083.     pop    di
  1084.     pop    es
  1085.     mov    dh, CANT_SEND
  1086.     stc
  1087.     ret
  1088.  
  1089. snd_frags_ok:
  1090.     lea    di, snd_bufs
  1091.     push    cx
  1092.     mov    cx, dx
  1093.     mov    bx, 0
  1094.     mov    al, 0
  1095.  
  1096. snd_free_chk:
  1097.     or    al, es:[di+bx].u_ecb.ecb_inuse
  1098.     add    bx, SIZE u_buf
  1099.     loop    snd_free_chk
  1100.  
  1101.     pop    cx
  1102.     or    al, al
  1103.     jnz    snd_err
  1104.  
  1105.     mov    dh, dl
  1106.     mov    dl, 1
  1107.     mov    bx, 0
  1108.     inc    FragmentID
  1109.     push    di
  1110.  
  1111. snd_next_frag:
  1112. ;
  1113. ; dh = total number of fragments to send
  1114. ; dl = current fragment
  1115. ; bx = offset into client buffer (ds:si) for this fragment
  1116. ; cx = bytes to go
  1117. ; es:di = address of current fragment's ecb
  1118. ;
  1119.  
  1120. ;determine next hop
  1121.  
  1122.     call    route        ; XXX, should be done for first fragment only!
  1123.     jnc    snd_frag1
  1124.     pop    di
  1125.     jmp    snd_err
  1126.  
  1127. snd_frag1:
  1128. ;fill in ecb
  1129.     mov    ax, 0
  1130.     mov    es:[di].u_ecb.ecb_esr.offs, ax
  1131.     mov    es:[di].u_ecb.ecb_esr.segm, ax
  1132.  
  1133.     mov    es:[di].u_ecb.ecb_sock, IP_socket
  1134.  
  1135.     mov    es:[di].u_ether_frag.ef_fragtot, dh
  1136.     mov    es:[di].u_ether_frag.ef_fragno, dl
  1137.     mov    ax, FragmentID
  1138.     mov    es:[di].u_ether_frag.ef_fragid, ax
  1139.  
  1140.     mov    ax, ds
  1141.     mov    es:[di].u_data_frag.frag_addr.segm, ax
  1142.  
  1143.     mov    ax, MAX_PAYLOAD
  1144.     sub    cx, ax
  1145.     jnc    snd_frag2
  1146.     add    ax, cx
  1147.  
  1148. snd_frag2:
  1149.     mov    es:[di].u_data_frag.frag_size, ax
  1150.     push    si
  1151.     add    si, bx
  1152.     mov    es:[di].u_data_frag.frag_addr.offs, si
  1153.     add    bx, ax
  1154.  
  1155. ;
  1156. ; es:si -> ecb to ship
  1157. ;
  1158.  
  1159.     mov    si, di
  1160.     call_ipx    SEND_PACKET,es,di,dx,cx,bx
  1161.     pop    si    ; ds:si -> client buffer once more
  1162.  
  1163.     add    di, SIZE u_buf    ; next send buffer
  1164.     inc    dl
  1165.     cmp    dl, dh
  1166.     jbe    snd_next_frag
  1167.  
  1168.     pop    di
  1169.  
  1170. ;simple timeout on sends
  1171.     mov    cx, 0ffffh
  1172.  
  1173. snd_wait:
  1174. ;wait until sends are done
  1175.     sti
  1176.     mov    bx, 0
  1177.     push    cx
  1178.     mov    ch, 0
  1179.     mov    cl, dh        ; dh still has fragment count
  1180.     mov    al, 0
  1181. snd_wait1:
  1182.     or    al, es:[di+bx].u_ecb.ecb_inuse
  1183.     add    bx, SIZE u_buf
  1184.     loop    snd_wait1
  1185.     pop    cx
  1186.  
  1187.     or    al, al
  1188.     jz    snd_done
  1189.     call_ipx    RELINQUISH,es,di,dx,cx
  1190.     loop    snd_wait
  1191.  
  1192. ;arrive here on timeout, cancel IPX sends
  1193.     mov    ch, 0
  1194.     mov    cl, dh
  1195.     mov    si, di
  1196.  
  1197. snd_cancel:
  1198.     call_ipx    CANCEL_EVENT,es,si,cx
  1199.     add    si, SIZE u_buf
  1200.     loop    snd_cancel
  1201.     jmp    snd_err
  1202.  
  1203. snd_done:
  1204. ;check completion status of send buffers
  1205.     mov    bx, 0
  1206.     mov    ch, 0
  1207.     mov    cl, dh
  1208.     mov    al, 0
  1209. snd_done1:
  1210.     or    al, es:[di+bx].u_ecb.ecb_cmplt
  1211.     add    bx, SIZE u_buf
  1212.     loop    snd_done1
  1213.  
  1214.     or    al, al
  1215.     jz    snd_ok
  1216.     jmp    snd_err
  1217.  
  1218. snd_ok:
  1219.     pop    di
  1220.     pop    es
  1221.     ret
  1222.  
  1223.     public    get_address
  1224. get_address:
  1225. ;get the address of the interface.
  1226. ;enter with es:di -> place to get the address, cx = size of address buffer.
  1227. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  1228.     assume    ds:code
  1229.     cmp    cx, EADDR_LEN
  1230.     jnb    ga_0
  1231.  
  1232.     stc
  1233.     ret
  1234.  
  1235. ga_0:
  1236.     push    si
  1237.     cmp    init_cmplt, 1
  1238.     jnc    ga_1
  1239.     call    listen_init
  1240.     mov    init_cmplt, 1
  1241.  
  1242. ga_1:
  1243.     lea    si, my_node_address    ; first copy IPX node address
  1244.     cld
  1245.     repmov    <EADDR_LEN>
  1246.  
  1247.     mov    cx, EADDR_LEN        ; if not significant enough,
  1248.     cmp    no_bytes, 0ffffh    ; magic in no_bytes?
  1249.     jne    ga_3
  1250.     lea    bx, my_node_address    ; they don't know
  1251.     mov    dx, bx            ; figure out something for no_bytes
  1252.     add    dx, SIZE my_node_address    ; savety
  1253.     mov    no_bytes, EADDR_LEN
  1254.  
  1255. ga_2:
  1256.     cmp    word ptr [bx], 0
  1257.     jnz    ga_3
  1258.     dec    no_bytes
  1259.     inc    bx
  1260.     cmp    bx, dx
  1261.     je    ga_3
  1262.     jmp    ga_2
  1263.  
  1264. ga_3:
  1265.     sub    cx, no_bytes        ; copy some of IPX net address
  1266.     jcxz    get_addr_x
  1267.     cmp    cx, SIZE my_net_address
  1268.     jbe    ga_4
  1269.     mov    cx, SIZE my_net_address
  1270. ga_4:
  1271.     lea    si, my_net_address
  1272.     sub    di, EADDR_LEN
  1273.  
  1274. ;next are three different methods for constructing the reported ethernet address
  1275. ;from a less-than-6-bytes-long IPX node adress and the IPX net address.
  1276. if ETH_CONSTR eq 1
  1277.  
  1278.     rep    movsb
  1279.  
  1280. elseif ETH_CONSTR eq 2
  1281.  
  1282. ga_21:
  1283.     mov    bx, SIZE my_net_address - 1
  1284.     mov    al, [si+bx]
  1285.     stosb
  1286.     dec    bx
  1287.     loop    ga_21
  1288.  
  1289. elseif ETH_CONSTR eq 3
  1290.  
  1291.     push    di
  1292.     push    si
  1293.     push    es
  1294.     mov    ax, ds
  1295.     mov    es, ax
  1296.     lea    di, dummy
  1297.     repmov    <SIZE my_net_address>
  1298.     pop    es
  1299.     pop    si
  1300.     pop    di
  1301.  
  1302.     lea    si, dummy
  1303.  
  1304. ga_3_loop:
  1305.     mov    bx, 0
  1306.     mov    dx, 0
  1307.     mov    al, 0
  1308. ga_31:
  1309.     cmp    bx, SIZE my_net_address
  1310.     jz    ga_33
  1311.     mov    ah, [si+bx]
  1312.     cmp    al, ah
  1313.     jnc    ga_32
  1314.     mov    al, ah
  1315.     mov    dx, bx
  1316. ga_32:
  1317.     inc    bx
  1318.     jmp    ga_31
  1319. ga_33:
  1320.     stosb
  1321.     mov    bx, dx
  1322.     mov    word ptr [si+bx], 0
  1323.     loop    ga_3_loop
  1324.     
  1325. endif
  1326.  
  1327.  
  1328. get_addr_x:
  1329.     mov    cx, EADDR_LEN
  1330.     pop    si
  1331.     clc
  1332.     ret
  1333.  
  1334. listen_init    proc    near
  1335. ;and start listening on each receive buffer
  1336.     push    si
  1337.     push    cx
  1338.     push    es
  1339.     mov    ax, cs
  1340.     mov    es, ax
  1341.     mov    cx, NO_OF_RCV_BUFS
  1342.     lea    si, rcv_bufs
  1343. li_1:
  1344.     call    listen_proc
  1345.     add    si, SIZE u_buf
  1346.     loop    li_1
  1347.     pop    es
  1348.     pop    cx
  1349.     pop    si
  1350.     ret
  1351. listen_init    endp
  1352.  
  1353.  
  1354.     public    set_address
  1355. set_address:
  1356. ;enter with ds:si -> Ethernet address, CX = length of address.
  1357. ;exit with nc if okay, or cy, dh=error if any errors.
  1358.     assume    ds:nothing
  1359.     ret
  1360.  
  1361.  
  1362. rcv_mode_3:
  1363. ;receive mode 3 is the only one we support, so we don't have to do anything.
  1364.     ret
  1365.  
  1366.  
  1367.     public    set_multicast_list
  1368. set_multicast_list:
  1369. ;enter with es:di ->list of multicast addresses, cx = number of bytes.
  1370. ;return nc if we set all of them, or cy,dh=error if we didn't.
  1371.     mov    dh,NO_MULTICAST
  1372.     stc
  1373.     ret
  1374.  
  1375.  
  1376.     public    get_multicast_list
  1377. get_multicast_list:
  1378. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  1379. ;return cy, NO_ERROR if we don't remember all of the addresses ourselves.
  1380. ;return cy, NO_MULTICAST if we don't implement multicast.
  1381.     mov    dh,NO_MULTICAST
  1382.     stc
  1383.     ret
  1384.  
  1385.  
  1386.     public    reset_interface
  1387. reset_interface:
  1388. ;reset the interface.
  1389.     assume    ds:code
  1390.     ret
  1391.  
  1392.  
  1393. ;called when we want to determine what to do with a received packet.
  1394. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  1395.     extrn    recv_find: near
  1396.  
  1397. ;called after we have copied the packet into the buffer.
  1398. ;enter with ds:si ->the packet, cx = length of the packet.
  1399.     extrn    recv_copy: near
  1400.  
  1401.     extrn    count_in_err: near
  1402.     extrn    count_out_err: near
  1403.  
  1404.     public    recv
  1405. recv:
  1406. ;called from the recv isr.  All registers have been saved, and ds=cs.
  1407. ;Upon exit, the interrupt will be acknowledged.
  1408.     assume    ds:code
  1409.     ret
  1410.  
  1411.  
  1412.     public    recv_exiting
  1413. recv_exiting:
  1414. ;called from the recv isr after interrupts have been acknowledged.
  1415. ;Only ds and ax have been saved.
  1416.     assume    ds:nothing
  1417.     ret
  1418.  
  1419.     public    terminate
  1420. terminate:
  1421. ;called when this driver should cease operation.
  1422.     assume    ds:nothing
  1423.  
  1424. ;close socket, outstanding listens should be cancelled automatically
  1425.     mov    dx, IP_socket
  1426.     call_ipx    CLOSE_SOCKET
  1427.  
  1428. ;    mov    ax, cs
  1429. ;    mov    es, ax
  1430. ;    mov    cx, NO_OF_RCV_BUFS
  1431. ;    lea    si, rcv_bufs
  1432. ;
  1433. ;terminate_1:
  1434. ;    call_ipx    CANCEL_EVENT,es,si,cx
  1435. ;    add    si, SIZE u_buf
  1436. ;    loop    terminate_1
  1437.  
  1438.     ret
  1439.  
  1440.  
  1441. ;any code after this will not be kept after initialization.
  1442. end_resident    label    byte
  1443.  
  1444.  
  1445.     public    usage_msg
  1446. usage_msg    db    "usage: ipx_pkt [-n] [-d] [-w] <packet_int_no>",CR,LF,'$'
  1447.  
  1448.     public    copyright_msg
  1449. copyright_msg    db    "Packet driver for IPX, version ",'0'+majver,".",'0'+version,CR,LF
  1450.         db    "Portions Copyright 1990, P. Kranenburg",CR,LF,'$'
  1451.  
  1452. no_ipx_msg    db    "IPX not present",CR,LF, '$'
  1453. wrong_sock_msg    db    "IPX has no good socket",CR,LF, '$'
  1454. ifdef DEBUG
  1455. debugmsg1    db    "Doing a GET TARGET",CR,LF, '$'
  1456. debugmsg2    db    "Past GET TARGET",CR,LF, '$'
  1457. debugmsg3    db    "Past GET ADDRESS",CR,LF, '$'
  1458. endif
  1459.  
  1460.     extrn    set_recv_isr: near
  1461.  
  1462. ;enter with si -> argument string, di -> word to store.
  1463. ;if there is no number, don't change the number.
  1464.     extrn    get_number: near
  1465.     extrn    skip_blanks: near
  1466.  
  1467.     public    parse_args
  1468. parse_args:
  1469.  
  1470.     call    skip_blanks
  1471.     cmp    byte ptr [si], CR
  1472.     je    parse_args_x
  1473.     cmp    byte ptr [si], '-'
  1474.     jne    parse_err
  1475.     cmp    byte ptr [si+1],'n'    ; '-n'?
  1476.     je    parse_args_1
  1477.  
  1478. parse_err:
  1479.     stc                ;no, must be an error.
  1480.     ret
  1481.  
  1482. parse_args_1:
  1483.     add    si, 2
  1484.     call    skip_blanks
  1485.     cmp    byte ptr [si], CR
  1486.     jne    parse_args_2
  1487.     mov    no_bytes, 0ffffh    ;try heuristic
  1488.     jmp    parse_args_x
  1489.  
  1490. parse_args_2:
  1491.     mov    di,offset no_bytes
  1492.     call    get_number
  1493.     cmp    no_bytes, 0
  1494.     jb    parse_err
  1495.     cmp    no_bytes, EADDR_LEN
  1496.     ja    parse_err
  1497.  
  1498. parse_args_x:
  1499.     clc
  1500.     ret
  1501.  
  1502.  
  1503.     public    etopen
  1504. etopen:
  1505.  
  1506. ;first see if IPX is there
  1507.     mov    ax, 07A00h
  1508.     int    2fh
  1509.     cmp    al, 0ffh
  1510.     je    ipx_is_here
  1511.     print$    no_ipx_msg
  1512.     stc
  1513.     ret
  1514.  
  1515. ipx_is_here:
  1516.     mov    ax, es
  1517.     mov    IPXentry.offs, di
  1518.     mov    IPXentry.segm, ax
  1519.  
  1520. ;close socket first, since "head" won't notify us on termination
  1521.     mov    dx, IP_socket
  1522.     call_ipx    CLOSE_SOCKET
  1523.  
  1524. ;next open socket
  1525.     mov    al, 0ffh        ; stay open until explicitly closed
  1526.     mov    dx, IP_socket
  1527.     call_ipx    OPEN_SOCKET
  1528.     or    al, 0
  1529.     jnz    wrong_socket
  1530.     cmp    dx, IP_socket
  1531.     je    good_socket
  1532.  
  1533. ;close socket and exit
  1534. wrong_socket:
  1535.     call_ipx    CLOSE_SOCKET
  1536.     print$    wrong_sock_msg
  1537.     stc
  1538.     ret
  1539.  
  1540. good_socket:
  1541. ;init send buffer fragment list
  1542.     mov    ax, cs
  1543.     mov    es, ax
  1544.  
  1545.     mov    cx, NO_OF_SND_BUFS
  1546.     lea    si, snd_bufs
  1547.  
  1548. et_1:
  1549.     mov    es:[si].u_ecb.ecb_fragcnt, NO_OF_FRAGMENTS
  1550.  
  1551.     mov    bx, si            ; bx = offset ipx_header
  1552.     add    bx, u_ipx
  1553.     mov    es:[si].u_ipx_frag.frag_addr.offs, bx
  1554.     mov    es:[si].u_ipx_frag.frag_addr.segm, ax
  1555.     mov    es:[si].u_ipx_frag.frag_size, SIZE ipx_header
  1556.  
  1557.     mov    bx, si            ; bx = offset ether_frag
  1558.     add    bx, u_ether_frag
  1559.     mov    es:[si].u_frag_frag.frag_addr.offs, bx
  1560.     mov    es:[si].u_frag_frag.frag_addr.segm, ax
  1561.     mov    es:[si].u_frag_frag.frag_size, SIZE ether_frag
  1562. ;
  1563. ; NOTE: u_data_frag is initialised send_pkt with address of user data buffer
  1564. ;
  1565.     add    si, SIZE u_buf
  1566.     loop    et_1
  1567.  
  1568. ;initialise receive buffer ipx data fragment addresses
  1569. ;and start listening on each
  1570.     mov    cx, NO_OF_RCV_BUFS
  1571.     lea    si, rcv_bufs
  1572.     lea    di, end_resident
  1573.  
  1574. et_2:
  1575.     mov    es:[si].u_ecb.ecb_fragcnt, NO_OF_FRAGMENTS
  1576.  
  1577.     mov    bx, si
  1578.     add    bx, u_ipx
  1579.     mov    es:[si].u_ipx_frag.frag_addr.offs, bx
  1580.     mov    es:[si].u_ipx_frag.frag_addr.segm, ax
  1581.     mov    es:[si].u_ipx_frag.frag_size, SIZE ipx_header
  1582.  
  1583.     mov    bx, si
  1584.     add    bx, u_ether_frag
  1585.     mov    es:[si].u_frag_frag.frag_addr.offs, bx
  1586.     mov    es:[si].u_frag_frag.frag_addr.segm, ax
  1587.     mov    es:[si].u_frag_frag.frag_size, SIZE ether_frag
  1588.  
  1589.     mov    es:[si].u_data_frag.frag_addr.offs, di        ; di = offset data buffer
  1590.     mov    es:[si].u_data_frag.frag_addr.segm, ax
  1591.     mov    es:[si].u_data_frag.frag_size, MAX_PAYLOAD
  1592.  
  1593.     add    si, SIZE u_buf
  1594.     add    di, MAX_PAYLOAD
  1595.     loop    et_2
  1596.  
  1597. ;heuristic to force network traffic which seems to necessary before
  1598. ;the GET_NODE_ADDRESS call will work properly (boo,hiss)
  1599.  
  1600. ;get our address
  1601.     sti
  1602.     lea    si, my_net_address
  1603.     call_ipx    GET_NODE_ADDRESS,es,si
  1604.     lea    si, my_net_address
  1605.     cmp    byte ptr es:[si], 0
  1606.     jne    et_3
  1607.     cmp    byte ptr es:[si+1], 0
  1608.     jne    et_3
  1609.     cmp    byte ptr es:[si+2], 0
  1610.     jne    et_3
  1611.     cmp    byte ptr es:[si+3], 0
  1612.     jne    et_3
  1613.  
  1614. ifdef TRY_GET_LOCAL_TARGET
  1615. ifdef DEBUG
  1616.     push    es
  1617.     print$    debugmsg1
  1618.     pop    es
  1619. endif
  1620.     lea    si, dummy
  1621.     mov    di, si
  1622.     add    di, 12
  1623.     call_ipx    GET_LOCAL_TARGET,es
  1624. ifdef DEBUG
  1625.     push    es
  1626.     print$    debugmsg2
  1627.     pop    es
  1628. endif
  1629.  
  1630. ;get our address
  1631.     lea    si, my_net_address
  1632.     call_ipx    GET_NODE_ADDRESS,es,si
  1633. ifdef DEBUG
  1634.     push    es
  1635.     push    si
  1636.     print$    debugmsg3
  1637.     pop    si
  1638.     pop    es
  1639. endif
  1640. endif
  1641.  
  1642. et_3:
  1643. ;initialise routing table with the broadcast address
  1644.     cld
  1645.     lea    di, rte
  1646.     mov    rte_end, di            ; rte_end = second entry
  1647.     add    rte_end, SIZE rt_ent        ;
  1648.     mov    rte_scache, di            ; rte_cache = first (and only) entry
  1649.     mov    rte_rcache, di            ; 
  1650.     mov    es:[di].rt_age, 0
  1651.     mov    es:[di].rt_x_pkt, GBP        ; broadcast packet type
  1652. ;;    mov    es:[di].rt_trail, 1        ; uses trail
  1653.  
  1654.     add    di, rt_ether            ; broadcast address
  1655.     mov    al, 0ffh
  1656.     mov    cx, SIZE rt_ether
  1657.     rep    stosb
  1658.  
  1659.     push    ds
  1660.     mov    ax, cs
  1661.     mov    ds, ax
  1662.     mov    cx, SIZE rt_net
  1663.     rep    movsb                ; net field set from my_net_address
  1664.     pop    ds
  1665.  
  1666.     mov    al, 0ffh
  1667.     mov    cx, SIZE rt_node + SIZE rt_gate
  1668.     rep    stosb                ; all FF's
  1669.  
  1670. ;schedule periodic aging of route table entries
  1671.     lea    si, rte_aes
  1672.     mov    ax, cs
  1673.     mov    es:[si].aes_esr.segm, ax
  1674.     mov    es:[si].aes_esr.offs, offset rte_ticker
  1675.     mov    ax, RTE_TICK
  1676.     call_ipx    SCHEDULE_SPECIAL_EVENT, es
  1677.  
  1678.  
  1679. ;if all is okay,
  1680.     mov    dx,offset end_resident
  1681.     add    dx, NO_OF_RCV_BUFS * MAX_PAYLOAD
  1682.     clc
  1683.     ret
  1684.  
  1685. ;if we got an error,
  1686.     stc
  1687.     ret
  1688.  
  1689.     public    print_parameters
  1690. print_parameters:
  1691.     ret
  1692.  
  1693. code    ends
  1694.  
  1695.     end
  1696.